#include "app_buffer.h"


/**
 * @brief 初始化缓冲区
 * @param total_size 缓冲区总大小 因为是双缓冲结构，所以总大小为2倍
 * @return 缓冲区指针
 *  创建两个缓冲区，一个用于读，一个用于写 放入一个主缓冲区中
 */
buffer_t *app_buffer_init(int total_size)
{
    // 主缓冲区
    buffer_t *buffer = (buffer_t *)malloc(sizeof(buffer_t));
    if (buffer == NULL)
    {
        log_error("buffer malloc error");
    }
    for (int i = 0; i < 2; i++)
    {
        buffer->sub_buffer[i] = (sub_buffer_t *)malloc(sizeof(sub_buffer_t));
        buffer->sub_buffer[i]->data = (char *)malloc(total_size);
        buffer->sub_buffer[i]->len = 0;
        buffer->sub_buffer[i]->total_size = total_size;
    }
    // 确定读写职责
    buffer->read_index = 0;
    buffer->write_index = 1;
    pthread_mutex_init(&buffer->read_lock, NULL);
    pthread_mutex_init(&buffer->swap_lock, NULL);
    return buffer;
}

/**
 * @brief 往缓冲区写入数据
 * @param buffer 缓冲区指针
 * @param data 写入的数据
 * @param len 写入的数据长度
 * @return 写入成功返回 0，失败返回-1
 * 1 判断是否可以写入数据 比较写入的数据长度和剩余空间大小
 * 2 如果可以写入数据 向尾部拷贝数据 更新当前数据的长度
 */
int app_buffer_write(buffer_t *buffer, char *data, u_int8_t len)
{
    pthread_mutex_lock(&buffer->swap_lock);
    // 0 取的当前负责写入的缓冲区
    sub_buffer_t *write_sub_buffer = buffer->sub_buffer[buffer->write_index];
    // 1 判断是否可以写入数据 比较写入的数据长度和剩余空间大小
    int remain_len = write_sub_buffer->total_size - write_sub_buffer->len;
    if (len > remain_len)
    {
        log_error("app_buffer_write error");
        return -1;
    }

    // 2 如果可以写入数据 向尾部拷贝数据 更新当前数据的长度
    // memcpy(write_sub_buffer->data + write_sub_buffer->len, (char *)len, 1);
    write_sub_buffer->data[write_sub_buffer->len] = len;
    memcpy(write_sub_buffer->data + write_sub_buffer->len + 1, data, (size_t)len);
    write_sub_buffer->len += (len + 1);
    pthread_mutex_unlock(&buffer->swap_lock);
    return 0;
}

static void app_buffer_swap(buffer_t *buffer)
{
    log_debug("app_buffer_swap");
    pthread_mutex_lock(&buffer->swap_lock);
    buffer->read_index = buffer->read_index == 0 ? 1 : 0;
    buffer->write_index = buffer->write_index == 0 ? 1 : 0;
    pthread_mutex_unlock(&buffer->swap_lock);
}


/**
 * @brief 从缓冲区读取数据
 * @param buffer 主缓冲区指针
 * @param read_buff 读取数据的容器 （已开辟的空间）
 * @param buff_len 读取数据容器长度
 * @return 读取成功返回读取的长度，失败返回-1
 * 
 * 1 判断容器i是否能够放一条数据 比较 容器长度 和 当前数据的长度
 * 2 判断当前读缓冲是否为空 要做切换
 * 3 读取数据 --> 从缓冲区开头位置读取一条数据 --> 从缓冲区中删除数据 --> 更新当前数据的长度
 * 4 如果读缓冲区为空 要做切换
 */
int app_buffer_read(buffer_t *buffer, char *read_buff, int buff_len)
{
    //  加锁
    pthread_mutex_lock(&buffer->read_lock);
    sub_buffer_t *read_sub_buffer = buffer->sub_buffer[buffer->read_index];
    // 判断当前读缓冲是否为空 要做切换
    if (read_sub_buffer->len == 0)
    {
        app_buffer_swap(buffer);
        read_sub_buffer = buffer->sub_buffer[buffer->read_index];
        /* code */
        if (read_sub_buffer->len == 0)
        {
            log_error("read_sub_buffer->data is null");
            return 0;
        }
        
    }

    // 判断容器i是否能够放一条数据 比较 容器长度 和 当前数据的长度
    int data_len = read_sub_buffer->data[0];
    if (buff_len < data_len)
    {
        log_error("buff_len < data_len");
        return 0;
    }
    
    // 读取数据 --> 从缓冲区开头位置读取一条数据 --> 从缓冲区中删除数据 --> 更新当前数据的长度
    memcpy(read_buff, read_sub_buffer->data + 1, data_len);
    memmove(read_sub_buffer->data, read_sub_buffer->data + data_len + 1, read_sub_buffer->len - data_len - 1);
    read_sub_buffer->len -= (data_len + 1);

    if (read_sub_buffer->len == 0)
    {
        app_buffer_swap(buffer);
        read_sub_buffer = buffer->sub_buffer[buffer->read_index];
    }
    pthread_mutex_unlock(&buffer->read_lock);
    return data_len;
}

// 销毁缓冲区
// 释放子缓冲去数据 在释放主缓冲区
void app_buffer_destroy(buffer_t *buffer)
{
    for (int i = 0; i < 2; i++)
    {
        free(buffer->sub_buffer[i]->data);
        free(buffer->sub_buffer[i]);
    }
    pthread_mutex_destroy(&buffer->read_lock);
    pthread_mutex_destroy(&buffer->swap_lock);
    free(buffer);
    
}

